/*
 * TAccesser.cpp
 *
 *  Created on: 2012-10-30
 *      Author: minhua
 */

#include "TAccesser.h"
#include "../TContext.h"
#include "../utils/TConverter.h"
#include "TNetworkAccessManager.h"
#include <QFile>
#include <QFileInfo>
#include "HttpPostDevice.h"

TAccesser::TAccesser(TSessionPointer session, QObject *parent) : QObject(parent)
{
	_session = session;
	_timer = NULL;
}

TAccesser::~TAccesser()
{
	TContext::instance()->logger()->debug("Accesser Deleted");
	if(_timer)
		delete _timer;
}

void TAccesser::request(QString path, int msec)
{
	QHash<QString, QVariant> variables;
	request(path, variables, msec);
}

void TAccesser::request(QString path, QHash<QString, QVariant> variables, int msec)
{
	variables.insert("version", TContext::instance()->config()->version());
	variables.insert("token", _session->getToken());

	TContext::instance()->logger()->debug("********* One Request *********");
	TContext::instance()->logger()->debug("Url: " + TContext::instance()->config()->serverUrl() + "/" + path);
	TContext::instance()->logger()->debug("Method: POST");

	//QNetworkAccessManager *manager = new QNetworkAccessManager(this);
	//connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(done(QNetworkReply *)));
	connect(TNetworkAccessManager::instance(), SIGNAL(done(QNetworkReply *)), this, SLOT(done(QNetworkReply *)));
	QUrl url(TContext::instance()->config()->serverUrl() + "/" + path);
	QNetworkRequest request;
	request.setUrl(url);
	QByteArray content;
	QHashIterator<QString, QVariant> iterator(variables);
	while(iterator.hasNext())
	{
		if(iterator.hasPrevious())
		{
			content.append("&");
		}
		QString key = iterator.next().key();
		content.append(key);
		content.append("=");

		QVariant value = variables.value(key);
		switch(value.type())
		{
		case QVariant::Int:
			content.append(QString::number(value.toInt()));
			break;
		case QVariant::Double:
			content.append(QString::number(value.toDouble()));
			break;
		case QVariant::String:
			content.append(value.toString().toUtf8());
			break;
		case QVariant::Date:
			content.append(TConverter::dateToString(value.toDate()));
			break;
		case QVariant::Time:
			content.append(TConverter::timeToString(value.toTime()));
			break;
		case QVariant::DateTime:
			content.append(TConverter::datetimeToString(value.toDateTime()));
			break;
		case QVariant::Bool:
			content.append(TConverter::boolToString(value.toBool()));
			break;
		default:
			break;
		}
	}
	content.replace('%', "%25");
	content.replace('+', "%2b");
	TContext::instance()->logger()->debug("Content: " + content);
	request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
	request.setHeader(QNetworkRequest::ContentLengthHeader, content.length());

	if (_timer != NULL)
		delete _timer;

	_path = TContext::instance()->config()->serverUrl() + "/" + path;
	_content = content;

	_timer = new QTimer();
	_timer->start(msec);

	connect(_timer, SIGNAL(timeout()), this, SLOT(timeout()));

	_reply = TNetworkAccessManager::instance()->post(request, content);
	connect(_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SIGNAL(downloadProgress(qint64, qint64)));
	connect(_reply, SIGNAL(uploadProgress(qint64, qint64)), this, SIGNAL(uploadProgress(qint64, qint64)));

	//_reply = manager->post(request, content);
}

void TAccesser::request(QString path, QHash<QString, QVariant> variables, QHash<QString, QString> files, int msec)
{
	QList<TFileVariable> fileList;
	QHashIterator<QString, QString> fileIterator(files);
	while(fileIterator.hasNext())
	{
		TFileVariable file;
		file.Key = fileIterator.peekNext().key();
		file.FileLocation = fileIterator.peekNext().value();
		file.StartPos = 0;
		file.TotalBytes = -1;
		fileList.append(file);
		fileIterator.next();
	}
	request(path, variables, fileList, msec);
}

void TAccesser::request(QString path, QHash<QString, QVariant> variables, QList<TFileVariable> files, int msec)
{
	variables.insert("version", TContext::instance()->config()->version());
	variables.insert("token", _session->getToken());

	TContext::instance()->logger()->debug("********* One Request *********");
	TContext::instance()->logger()->debug("Url: " + TContext::instance()->config()->serverUrl() + "/" + path);
	TContext::instance()->logger()->debug("Method: POST");

	connect(TNetworkAccessManager::instance(), SIGNAL(done(QNetworkReply *)), this, SLOT(done(QNetworkReply *)));
	QUrl url(TContext::instance()->config()->serverUrl() + "/" + path);

	QString split = "---------------------------7dc92720f6c";
	QNetworkRequest request;
	request.setUrl(url);
	request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary="+split);

	QByteArray content;
	QHashIterator<QString, QVariant> iterator(variables);
	while(iterator.hasNext())
	{
		QString key = iterator.next().key();
		content.append("--" + split + "\r\n");
		content.append("Content-Disposition: ");
		content.append("form-data; name=\"" + key + "\"\r\n");
		content.append("\r\n");

		QVariant value = variables.value(key);
		switch(value.type())
		{
		case QVariant::Int:
			content.append(QString::number(value.toInt()));
			break;
		case QVariant::Double:
			content.append(QString::number(value.toDouble()));
			break;
		case QVariant::String:
			content.append(value.toString().toUtf8());
			break;
		case QVariant::Date:
			content.append(TConverter::dateToString(value.toDate()));
			break;
		case QVariant::Time:
			content.append(TConverter::timeToString(value.toTime()));
			break;
		case QVariant::DateTime:
			content.append(TConverter::datetimeToString(value.toDateTime()));
			break;
		case QVariant::Bool:
			content.append(TConverter::boolToString(value.toBool()));
			break;
		default:
			break;
		}
		content.append("\r\n");
	}

	QListIterator<TFileVariable> fileIterator(files);
	while(fileIterator.hasNext())
	{
		TFileVariable fileVar = fileIterator.next();
		QString key = fileVar.Key;
		QFile file(fileVar.FileLocation);
		if(file.exists() && file.open(QFile::ReadOnly))
		{
			QFileInfo fileInfo(fileVar.FileLocation);
			content.append("--" + split + "\r\n");
			content.append("Content-Disposition: ");
			content.append("form-data; name=\""+key+"\"; filename=\""+fileInfo.fileName().toUtf8()+"\"\r\n");
			//content.append("Content-Transfer-Encoding: binary\r\n");
			content.append("Content-Type: application/x-zip-compressed\r\n");
			content.append("\r\n");

			file.seek(fileVar.StartPos);
			QByteArray fileBuffer;
			if(fileVar.TotalBytes < 0)
			{
				fileBuffer = file.readAll();
			}
			else
			{
				fileBuffer = file.read(fileVar.TotalBytes);
			}

			TContext::instance()->logger()->debug("File Buffer Length: " + QString::number(fileBuffer.size()));
			content.append(fileBuffer);
			content.append("\r\n");
			file.close();
		}
	}
	content.append("--" + split + "--");
	content.append("\r\n");

	TContext::instance()->logger()->debug("Content: " + content);

	request.setHeader(QNetworkRequest::ContentLengthHeader, content.size());

	if (_timer != NULL)
		delete _timer;

	_path = TContext::instance()->config()->serverUrl() + "/" + path;
	//_content = content;

	_timer = new QTimer();
	_timer->start(msec);

	connect(_timer, SIGNAL(timeout()), this, SLOT(timeout()));

	_reply = TNetworkAccessManager::instance()->post(request, content);
	connect(_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SIGNAL(downloadProgress(qint64, qint64)));
	connect(_reply, SIGNAL(uploadProgress(qint64, qint64)), this, SIGNAL(uploadProgress(qint64, qint64)));
}

void TAccesser::done(QNetworkReply *reply)
{
	if (_reply != reply)
		return;

	if (_timer)
	{
		_timer->stop();
		delete _timer;
		_timer = NULL;
	}
	TContext::instance()->logger()->debug("********* One Request Done *********");
	TContext::instance()->logger()->debug("Error: " + QString::number((int)(reply->error())));

	QDomElement response;
	bool error = true;

	QByteArray responseBody = reply->readAll();
	TContext::instance()->logger()->debug("Response Body: " + QString::fromUtf8(responseBody));

	if(reply->error()==QNetworkReply::NoError)
	{
		//QByteArray responseBody = reply->readAll();
		//TContext::instance()->logger()->debug("Response Body: " + QString::fromUtf8(responseBody));
		QString errorMessage;
		int errorLine;
		int errorColumn;
		QDomDocument doc;
		if(!doc.setContent(responseBody, &errorMessage, &errorLine, &errorColumn))
		{
			TContext::instance()->logger()->error("Parse the requester response failed: " + QString::fromUtf8(responseBody));
			error = true;
		}
		else
		{
			response = doc.documentElement();
			QDomElement errorElement = response.firstChildElement("error");
			if(!errorElement.isNull())
			{
				TContext::instance()->logger()->error("Backbone request error: " + errorElement.attribute("code"));
				error = true;
			}
			else
			{
				error = false;
			}
		}
	}

	emit finished(error, response);
}

void TAccesser::timeout()
{
	QTimer *tmpTimer = (QTimer*)sender();
	tmpTimer->stop();
	tmpTimer->deleteLater();
	if (tmpTimer != _timer)
	{
		return;
	}
	_timer = NULL;
	TContext::instance()->logger()->debug(_path + "?" + _content + "  timeout");
	QDomElement response;
	emit finished(true, response);
}
